package com.liuyi.framework.web.jackson;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.liuyi.tools.kits.EnumsKits;

import java.io.IOException;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

/**
 * <p>
 * ObjectMapper 工具类
 * </p>
 *
 * @author Mr.Fmy
 * @since 2020-12-18
 */
public class ObjectMapperUtil {

    /**
     * 基本通用配置
     */
    public static void basicConfig(ObjectMapper om) {
        //接受单个字符的值反序列化为数组。
        om.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        // 启用属性名特征
        om.configure(MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME, true);
        // 序列化的时候，不输出null值
        om.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // 从JSON到java object
        // 没有匹配的属性名称时不作失败处理
        om.configure(MapperFeature.AUTO_DETECT_FIELDS, true);
        // 禁止遇到未知（新）属性时报错，支持兼容扩展
        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 启用JSON空字符串的特性
        om.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
        // 启用强制非数组是可接受
        om.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        // 启用数字时间戳转日期
        om.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, true);

        // 序列化
        // 禁止序列化空值
        om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 按时间戳格式生成日期
        om.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, true);
        // 不包含空值属性
        om.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
        om.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // 是否缩放排列输出，默认false，有些场合为了便于排版阅读则需要对输出做缩放排列
        om.configure(SerializationFeature.INDENT_OUTPUT, false);
    }

    /**
     * IWEnum 枚举配置，这个是非常有用的，特别是在实体的情况下
     * 例如 枚举，会自动回家返回 枚举Cn
     * <p>
     * 只包含序列号，不包含反序列化
     * </p>
     */
    public static void iwEnumConfig(ObjectMapper om) {
        //枚举额外处理
        SimpleModule module = new SimpleModule();
        module.addSerializer(EnumsKits.IWEnum.class, new JsonSerializer<EnumsKits.IWEnum>() {
            @Override
            public void serialize(EnumsKits.IWEnum value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeString(((Enum) value).name());
                String currentName = gen.getOutputContext().getCurrentName();
                gen.writeStringField(currentName + "Cn", value.getD());
            }
        });
        om.registerModule(module);
    }

    /**
     * 关于转换JSON是否携带@Class
     */
    public static void classConfig(ObjectMapper om) {
        //开启 @class 属性
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
    }


    /**
     * java8字符串模式序列化配置
     */
    public static void java8TimeStrConfig(ObjectMapper om) {
        SimpleModule module = new SimpleModule();
        //序列化
        module.addSerializer(Timestamp.class, new JsonSerializer<Timestamp>() {
            @Override
            public void serialize(Timestamp value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeString(DateUtil.format(value, DatePattern.NORM_DATETIME_PATTERN));
            }
        });
        module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
        module.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
        module.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
        //反序列化
        module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
        module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
        module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
        om.registerModule(module);
    }
}
